{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数据的加载"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 数据集类\n",
    "在torch中提供了数据集的基类```torch.utils.data.Dataset```,继承这个基类，我们就可以很快速的实现对数据的加载"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```torch.utils.data.Dataset```源码如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Dataset(object):\n",
    "    def __getitem__(self, index):\n",
    "        raise NotImplementedError\n",
    "    \n",
    "    def __len__(self):\n",
    "        raise NotImplementedError\n",
    "    \n",
    "    def __add__(self, other):  # 把两个数据集合并在一起\n",
    "        return ConcateDataset([self, other])\n",
    "    "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我们需要在自定义的数据集类型继承Dataset类，同时还需要实现以下两个方法：<br/>\n",
    "1、```__len__```方法，能够实现通过全局的```len()```方法获取其中的元素的个数<br/>\n",
    "2、```__getitem__()```方法，能够通过传入的索引方式获取数据，例如通过```dataset[i]```获取其中第i条数据"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "('ham', 'Go until jurong point, crazy.. Available only in bugis n great world la e buffet... Cine there got amore wat...')\n",
      "5574\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from torch.utils.data import Dataset, DataLoader\n",
    "\n",
    "data_path = './SMSSpamCollection'\n",
    "\n",
    "# 完成数据集类\n",
    "class MyDataset(Dataset):\n",
    "    def __init__(self):\n",
    "        self.lines = open(data_path, encoding='gbk', errors='ignore').readlines()  # 一行一行的读取文件中的数据\n",
    "        # 对数据进行处理，前4个为label，后面的为短信内容,因为有空格，所以需要strip()函数进行处理\n",
    "#         lines = [[i[:4].strip(), i[4:].strip()] for i in self.lines]\n",
    "        \n",
    "    \n",
    "    def __getitem__(self, index):\n",
    "        # 获取索引对应位置的一条数据\n",
    "        cur_line = self.lines[index].strip()\n",
    "        # 对数据进行处理，前4个为label，后面的为短信内容,因为有空格，所以需要strip()函数进行处理\n",
    "        label = cur_line[: 4].strip()\n",
    "        content = cur_line[4: ].strip()\n",
    "        return label, content\n",
    "    \n",
    "    def __len__(self):\n",
    "        # 返回数据的总数量\n",
    "        return len(self.lines) \n",
    "    \n",
    "    \n",
    "if __name__ == '__main__':\n",
    "    my_dataset = MyDataset()\n",
    "#     print(my_dataset[0])\n",
    "#     print(len(my_dataset))\n",
    "    data_loader = DataLoader(dataset=my_dataset, batch_size=2, shuffle=True)\n",
    "    for i in data_loader:\n",
    "        print(i)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 迭代数据集\n",
    "在pytorch中```torch.utils.data.DataLoader```提供给了以下的方法\n",
    "- 批处理（Batching the data）\n",
    "- 打乱数据(shuffling the data)\n",
    "- 使用多线程multiprocessing并行加载数据"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "DataLoader的使用方法示例："
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "from torch.utils.data import DataLoader<br/>\n",
    "DataLoader(dataset,batch_size,shuffle,num_works,drop_last)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "其中参数的含义<br/>\n",
    "1.dataset:提前定义的数据集的实例<br/>\n",
    "2.batch_size:传入数据的batch的大小，常用128，256等等<br/>\n",
    "3.shuffle：bool类型，表示是否在每次获取数据的时候都提前打乱数据<br/>\n",
    "4.num_works:加载数据的线程数<br/>\n",
    "5.drop_last:bool类型，当除不尽的时候，最后一批数据就删除掉"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### pytorch中自带的数据集"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "pytorh中自带的数据集有两个上层api提供，分别是torchvision和torchtext<br/>\n",
    "其中：<br/>\n",
    "- 1.```torchvision```提供了对图片数据处理的相关api和数据\n",
    "    - 数据位置： ```torchvision.datasets```,例如： ```torchvision.datasets.MNIST```(手写数字识别图片数据)\n",
    "- 2.```torchtext```提供了对文本数据处理的相关api和数据\n",
    "    - 数据位置： ```torchtext.datasets```,例如： ```torchtext.datasets.IMDB```(手写数字识别图片数据)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 以手写数字识别为例子：\n",
    "60000个训练样本，10000个测试样本，图片大小28*28的黑白图像"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1、准备好Dataset实例<br/>\n",
    "2、把dataset交给dataloader，打乱顺序，组成batch"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "直接对```torchvision.datasets.MNIST```进行实例话就可以得到Dataset的实例，但是在使用MNISTAPI中的参数需要注意以下：<br/>\n",
    "torchvision.datasets.MNIST(root='/file/', train=True, download=True, transform=)<br/>\n",
    "- 1.root：参数表示数据存放的位置\n",
    "- 2.train: bool类型，表示是使用训练集的数据还是使用测试集的数据\n",
    "- 3.download：bool类型，表示是否需要下载数据到root目录\n",
    "- 4.transform: 实现的对图片的处理函数"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz to ./data\\MNIST\\raw\\train-images-idx3-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "99f3437ac3b94497b1c842aaced5518c",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(FloatProgress(value=1.0, bar_style='info', max=1.0), HTML(value='')))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data\\MNIST\\raw\\train-images-idx3-ubyte.gz to ./data\\MNIST\\raw\n",
      "Downloading http://yann.lecun.com/exdb/mnist/train-labels-idx1-ubyte.gz to ./data\\MNIST\\raw\\train-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "71e20d2893af4c2bb96759c987f5ca89",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(FloatProgress(value=1.0, bar_style='info', max=1.0), HTML(value='')))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data\\MNIST\\raw\\train-labels-idx1-ubyte.gz to ./data\\MNIST\\raw\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-images-idx3-ubyte.gz to ./data\\MNIST\\raw\\t10k-images-idx3-ubyte.gz\n",
      "\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "0570f41d7baf4ee3b1d7a58137aef3fc",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(FloatProgress(value=1.0, bar_style='info', max=1.0), HTML(value='')))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data\\MNIST\\raw\\t10k-images-idx3-ubyte.gz to ./data\\MNIST\\raw\n",
      "Downloading http://yann.lecun.com/exdb/mnist/t10k-labels-idx1-ubyte.gz to ./data\\MNIST\\raw\\t10k-labels-idx1-ubyte.gz\n"
     ]
    },
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "8290bf584be44cd78e0e23a20cd92629",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "HBox(children=(FloatProgress(value=1.0, bar_style='info', max=1.0), HTML(value='')))"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Extracting ./data\\MNIST\\raw\\t10k-labels-idx1-ubyte.gz to ./data\\MNIST\\raw\n",
      "Processing...\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\WYJ\\anaconda3\\lib\\site-packages\\torchvision\\datasets\\mnist.py:469: UserWarning: The given NumPy array is not writeable, and PyTorch does not support non-writeable tensors. This means you can write to the underlying (supposedly non-writeable) NumPy array using the tensor. You may want to copy the array to protect its data or make it writeable before converting it to a tensor. This type of warning will be suppressed for the rest of this program. (Triggered internally at  ..\\torch\\csrc\\utils\\tensor_numpy.cpp:141.)\n",
      "  return torch.from_numpy(parsed.astype(m[2], copy=False)).view(*s)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Done!\n",
      "Dataset MNIST\n",
      "    Number of datapoints: 60000\n",
      "    Root location: ./data\n",
      "    Split: Train\n"
     ]
    }
   ],
   "source": [
    "# 下载数据集\n",
    "from torchvision.datasets import MNIST\n",
    "mnist = MNIST(root='./data', train=True, download=True)\n",
    "print(mnist)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "None\n"
     ]
    }
   ],
   "source": [
    "from torchvision.datasets import MNIST\n",
    "mnist = MNIST(root='./data', train=True, download=False)\n",
    "mnist[0][0].show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### pytorch实现手写数字识别"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1、思路：\n",
    "- a.准备数据\n",
    "- b.模型的构建\n",
    "- c.训练\n",
    "- d.模型的保存\n",
    "- e.模型的评估"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```torchvision.transforms.ToTensor```将(h, w, c)(高，宽，通道)转换成(c, h, w)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "```transforms.ToTensor()(img)```中的```transforms.ToTensor()```是一个类，所以能够调用其中的```__call__```方法，能够传入img"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "源码如下:<br/>\n",
    "class ToTensor(object):\n",
    "    \"\"\"Convert a ``PIL Image`` or ``numpy.ndarray`` to tensor.\n",
    "\n",
    "    Converts a PIL Image or numpy.ndarray (H x W x C) in the range\n",
    "    [0, 255] to a torch.FloatTensor of shape (C x H x W) in the range [0.0, 1.0]\n",
    "    if the PIL Image belongs to one of the modes (L, LA, P, I, F, RGB, YCbCr, RGBA, CMYK, 1)\n",
    "    or if the numpy.ndarray has dtype = np.uint8\n",
    "\n",
    "    In the other cases, tensors are returned without scaling.\n",
    "    \"\"\"\n",
    "\n",
    "    def __call__(self, pic):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            pic (PIL Image or numpy.ndarray): Image to be converted to tensor.\n",
    "\n",
    "        Returns:\n",
    "            Tensor: Converted image.\n",
    "        \"\"\"\n",
    "        return F.to_tensor(pic)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(2, 2, 3)\n",
      "tensor([[[105, 102],\n",
      "         [155, 115]],\n",
      "\n",
      "        [[193, 201],\n",
      "         [ 13, 173]],\n",
      "\n",
      "        [[190, 237],\n",
      "         [167, 224]]], dtype=torch.int32)\n",
      "torch.Size([3, 2, 2])\n"
     ]
    }
   ],
   "source": [
    "from torchvision import transforms\n",
    "import numpy as np\n",
    "\n",
    "data = np.random.randint(0, 255, size=12)\n",
    "img = data.reshape(2, 2, 3)  # h, w, c\n",
    "print(img.shape)\n",
    "img_tensor = transforms.ToTensor()(img) # 转换成tensor\n",
    "print(img_tensor)\n",
    "print(img_tensor.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(28, 28)\n",
      "torch.Size([1, 28, 28])\n"
     ]
    }
   ],
   "source": [
    "from torchvision import transforms\n",
    "from torchvision.datasets import MNIST\n",
    "mnist = MNIST(root='./data', train=True, download=False)\n",
    "print(mnist[0][0].size)  #  (28, 28)这里的1就直接省略了\n",
    "ret = transforms.ToTensor()(mnist[0][0])\n",
    "print(ret.size())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ```torchvision.transforms.Normalize(mean, std)```对图片进行归一化处理\n",
    "给定的均值和标准差的形状必须和图片的通道数是相同的，比如图片有3个通道，就使用mean形状[x, y, z]，会对图片你的每一个通道按照不同的均值和方差进行归一化处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "即：Normalized_img = (img - mean) / std"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "所以这边应该先转换成(c, w, h),然后在进行标准化处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 这里特别注意一下"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([[[101, 241],\n",
      "         [ 80,  70]],\n",
      "\n",
      "        [[218,  18],\n",
      "         [245,  48]],\n",
      "\n",
      "        [[ 18,  54],\n",
      "         [ 30, 100]]], dtype=torch.int32)\n",
      "**********\n"
     ]
    },
    {
     "ename": "RuntimeError",
     "evalue": "Integer division of tensors using div or / is no longer supported, and in a future release div will perform true division as in Python 3. Use true_divide or floor_divide (// in Python) instead.",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mRuntimeError\u001b[0m                              Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-24-028ed84dd0cd>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[0mmean\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtensor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m10\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfloat32\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     11\u001b[0m \u001b[0mstd\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtensor\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdtype\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mfloat32\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 12\u001b[1;33m \u001b[0mnorm_img\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mtransforms\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mNormalize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmean\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mstd\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mimg\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     13\u001b[0m \u001b[1;31m# norm_img = transforms.Normalize((10.0, 10.0, 10.0),(1.0, 10, 1.0))(img)  # 这边是三个通道，所以需要传递shape为3的mean和std\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     14\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnorm_img\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torchvision\\transforms\\transforms.py\u001b[0m in \u001b[0;36m__call__\u001b[1;34m(self, tensor)\u001b[0m\n\u001b[0;32m    210\u001b[0m             \u001b[0mTensor\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mNormalized\u001b[0m \u001b[0mTensor\u001b[0m \u001b[0mimage\u001b[0m\u001b[1;33m.\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    211\u001b[0m         \"\"\"\n\u001b[1;32m--> 212\u001b[1;33m         \u001b[1;32mreturn\u001b[0m \u001b[0mF\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnormalize\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtensor\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmean\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstd\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0minplace\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    213\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    214\u001b[0m     \u001b[1;32mdef\u001b[0m \u001b[0m__repr__\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m~\\anaconda3\\lib\\site-packages\\torchvision\\transforms\\functional.py\u001b[0m in \u001b[0;36mnormalize\u001b[1;34m(tensor, mean, std, inplace)\u001b[0m\n\u001b[0;32m    296\u001b[0m     \u001b[1;32mif\u001b[0m \u001b[0mstd\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mndim\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    297\u001b[0m         \u001b[0mstd\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mstd\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 298\u001b[1;33m     \u001b[0mtensor\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msub_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmean\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdiv_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mstd\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m    299\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[0mtensor\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m    300\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mRuntimeError\u001b[0m: Integer division of tensors using div or / is no longer supported, and in a future release div will perform true division as in Python 3. Use true_divide or floor_divide (// in Python) instead."
     ]
    }
   ],
   "source": [
    "from torchvision import transforms\n",
    "import numpy as np\n",
    "import torchvision\n",
    "\n",
    "data = np.random.randint(0, 255, size=12)\n",
    "img = data.reshape(2, 2, 3)\n",
    "img = transforms.ToTensor()(img)  # 先进行转化\n",
    "print(img)\n",
    "print('*' *10)\n",
    "mean = torch.tensor([10, 10, 10], dtype=torch.float32)\n",
    "std = torch.tensor([1, 1, 1], dtype=torch.float32)\n",
    "norm_img = transforms.Normalize(mean, std)(img)\n",
    "# norm_img = transforms.Normalize((10.0, 10.0, 10.0),(1.0, 10, 1.0))(img)  # 这边是三个通道，所以需要传递shape为3的mean和std\n",
    "print(norm_img)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ```torchvision.transforms.Compose(transforms)```\n",
    "将多个```transform```组合起来"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "例如：<br/>\n",
    "```\n",
    "transforms.Compose([\n",
    "    torchvision.transforms.ToTensor(),  # 先转化为Tensor，h,w,c-->c,h,w\n",
    "    torchvision.transforms.Normalize(mean,std)  # 进行归一化\n",
    "])```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
